package xyz.weblade.lynchmybatis.utils.excel;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class MultiLevelExcelUtil<T> {


    private Class<T> clazz;

    List<String> fields;


    public MultiLevelExcelUtil(Class<T> clazz) {
        this.clazz = clazz;
        initialize();
    }

    private void initialize() {

        // 获取类上的注解
        fields = new ArrayList<>();
        getAllFields(clazz, fields);

    }


    //递归获取所有字段名称
    public void getAllFields(Class<?> clazz, List<String> fields) {
        Field[] declaredFields = clazz.getDeclaredFields();
        Field multiExcelNodeField = null;
        for (Field declaredField : declaredFields) {
            if (declaredField.isAnnotationPresent(MultiExcelNode.class)){
                multiExcelNodeField = declaredField;
                continue;
            }
            System.out.println("新增了"+declaredField.getName());
            fields.add(declaredField.getName());
        }
        if(multiExcelNodeField != null){
            ParameterizedType pt = (ParameterizedType) multiExcelNodeField.getGenericType();
            Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
            getAllFields(subClass, fields);
          }
    }


    public void exportExcel(List<T> dataList, String filePath,String sheetName) {

        if (dataList == null || dataList.isEmpty()){
            return;
        }

        if (filePath == null || filePath.isEmpty()){
            filePath = "out.xlsx";
        }

        if (sheetName == null || sheetName.isEmpty()){
            sheetName = "default";
        }

        List<TreeNode> rootNodes = dataList.stream().map(this::buildTreeNode).collect(Collectors.toList());
        buildExcel(rootNodes, filePath);
    }

    public  void buildExcel(List<TreeNode> rootNodes, String filePath) {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Data");
        //创建表头
        Row headRow = sheet.createRow(0);
        int headColIndex = 0;
        for (String field : fields) {
            headRow.createCell(fields.indexOf(field)).setCellValue(field);
            headColIndex++;
        }


        //需要判断每次新的节点的起始位置
        int startRow = 1;
        for (TreeNode rootNode : rootNodes) {
            CountTool countTool = new CountTool();
            int leafCount = countTool.countLeaves(rootNode);
            Map<TreeNode, Integer> leafCountCache = countTool.getLeafCountCache();

            processNode(sheet, rootNode, startRow, 0,leafCountCache);
            startRow+= leafCount;
        }

        try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
            workbook.write(fileOut);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void processNode(Sheet sheet, TreeNode node, int startRow, int startCol,Map<TreeNode, Integer> leafCountCache) {
        Object data = node.getData();
        Class<?> clazz = data.getClass();
        Field[] fields = clazz.getDeclaredFields();

        int currentColIndex = startCol;

        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(data);
                if (field.isAnnotationPresent(MultiExcelNode.class)) {
                    // 数据里面属于 @MultiExcelNode 的部分 是list，需要展开处理
                    if (value instanceof List) {
                        int rootLeafCount = leafCountCache.get(node);
                        int childLeafCountSum = 0;
                        List<TreeNode> childrenList = node.getChildren();
                        for (TreeNode childNode: childrenList) {
                            //打印出此时的startRow跟此时Node的数据
                            System.out.println("startRow:"+startRow+"  data:"+childNode.getData());
                            processNode(sheet,childNode,startRow,startCol+fields.length - 1,leafCountCache);
                            Integer childLeafCount = leafCountCache.get(childNode);
                            childLeafCountSum+=childLeafCount;
                            if (childLeafCountSum<rootLeafCount){
                                startRow+=childLeafCount;
                            }
                        }
                    }
                } else {
                    //如果不是列表类型，就在当前行新建一列，继续填充数值
                    Row row = sheet.getRow(startRow);
                    if (row == null) {
                        row = sheet.createRow(startRow);
                    }
                    Cell cell = row.createCell(currentColIndex);
                    currentColIndex++;
                    if (value != null) {
                        cell.setCellValue(value.toString());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


    }


    public TreeNode buildTreeNode(Object data) {
        TreeNode node = new TreeNode(data);
        // 用于判断需不需要添加成子节点
        Class<?> clazz = data.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(MultiExcelNode.class)) {
                field.setAccessible(true);
                try {
                    Object childList = field.get(data);
                    if (childList instanceof List) {
                        List<?> children = (List<?>) childList;
                        for (Object childData : children) {
                            TreeNode childNode = buildTreeNode(childData);
                            node.addChild(childNode);
                        }
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return node;
    }
   


}   